.XLIST
;			M80LIB00.MAC
;			renamed from
;			MACRO LIBRARY
;
;	Last Updated on:
;	23 June 1982
;	John S. Wilson
;
;	This is the MACRO-80 version of Digital Research's MAC macro 
;	assembler library MACRO.LIB.
;	Specific changes are:
;
;	1):  Tests for null arguments use IFB <arg> and IFNB <arg> 
;	2):  Argument lists for REPT/IRP/IRPC enclosed in angle brackets < >
;	3):  Argument lists for REPT/IRP/IRPC which contained bracketed 
;	     arguements within brackets altered to have single brackets
;	     (See SAVE and RESTORE in the original library)
;	4):  Labels are terminated with a colon.
;
;	As MACRO.LIB does not work with Microsoft's MACRO-80 (M80),
;	this library will not work with Digital Research's MAC.
;	Ain't that always the way, anyhow!!
;
; 
;******************************************************************************
;	SAVE MACRO	SAVE SPECIFIED REGISTERS
;
;	SAVE	R1,R2,R3,R4
;
;		R1-R4 MAY BE B,D,H OR PSW  SAVED IN ORDER SPECIFIED
;		IF REGS ARE OMITTED SAVE B,D AND H
;
SAVE	MACRO	R1,R2,R3,R4
	IFNB 	<R1&R2&R3&R4>		;;Altered form
	IRP	R,<R1,R2,R3,R4>
	IFB <R>				;;Altered form
	EXITM
	ENDIF
	PUSH	R
	ENDM
	ELSE
	IRPC	REG,<BDH>
	PUSH	REG
	ENDM
	ENDIF
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	RESTORE MACRO	RESTORE REGISTERS  (INVERSE OF SAVE)
;
;	RESTORE	R1,R2,R3,R4
;
;		R1-R4 MAY BE B,D,H OR PSW  RESTORED IN ORDER SPECIFIED
;		IF REGS OMITTED RESTORE H,D AND B
;
RESTORE	MACRO	R1,R2,R3,R4
	IFNB 	<R1&R2&R3&R4>		;;Altered form
	IRP	R,<R1,R2,R3,R4>
	IFB	<R>			;;Altered form
	EXITM
	ENDIF
	POP	R
	ENDM
	ELSE
	IRPC	REG,<HDB>
	POP	REG
	ENDM
	ENDIF
	ENDM
;
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	CHARIN MACRO	CONSOLE INPUT TO A
;
;	CHARIN	ADDR
;
CHARIN	MACRO	ADDR
	MVI	C,1		;;CONSOLE INPUT
	CALL	5		;;CALL BDOS
	IFNB 	<ADDR>		;;altered form
	STA	ADDR
	ENDIF
	ENDM
;
;
;	. . . . . . . . . . . . . . ... ... . .. . . . . . . . .
;
;	CHAROUT MACRO	CONSOLE OUTPUT FROM A
;
;	CHAROUT	ADDR
;
CHAROUT	MACRO	ADDR
	IFNB 	<ADDR>		;;Altered form
	LDA	ADDR
	ENDIF
	MVI	C,2		;;CONOUT
	MOV	E,A		;;CHAR TO E
	CALL	5		;;CALL BDOS
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	CHARSTAT MACRO	CHECK CONSOLE STATUS
;
;			RETURN TRUE (FF) IF CHAR READY FALSE (0) IF NOT
;
CHARSTAT MACRO
	LOCAL	EXIT
	MVI	C,11
	CALL	5
	ORA	A
	JZ	EXIT
	MVI	A,0FFH
EXIT:	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	INPUT MACRO	INPUT CHARACTER STRING FROM CONSOLE
;
;	INPUT	ADDR,BUFLEN
;
;		ADDR	START OF TEXT BUFFER
;		BUFLEN	LENGTH OF BUFFER  (DEFAULT IS 127)
;
INPUT	MACRO	ADDR,BUFLEN
	MVI	C,10
	IFNB 	<ADDR>		;;Altered form
	LXI	D,ADDR		;;SET BUFFER ADDRESS
	ENDIF
	IFNB 	<BUFLEN>	;;Altered form
	MVI	A,BUFLEN	;;SET BUFFER LENGTH
	STAX	D
	ELSE
	MVI	A,127
	STAX	D		;;SET BUFFER DEFAULT MAXIMUM
	ENDIF
	CALL	5		;;BDOS ENTRY
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	PRINT MACRO	PRINT A STRING ON CONSOLE
;
;	PRINT				(CARRIAGE RETURN, LINE FEED)
;	PRINT	'LITERAL'
;	PRINT	<'LITERAL',CR,LF,'SECOND LITERAL'>
;
;	PRINT	ADDR,$			(ASCII OUTPUT UNTIL $)
;	PRINT	ADDR,L,H		(HEX OUTPUT L CHARACTERS)
;
;	Note that for the following usage of the macro PRINT the string 
;	referenced by ADDR must contain (via db) enough characters to 
;	match the length requirement in L.  Stated another way L is 
;	--- NOT --- a character repeat specification but rather a spec.
;	to extract <L> characters from the string.
;	PRINT	ADDR,L,A		(ASCII OUTPUT L CHARACTERS)
;
;		LITERALS MUST BE IN SINGLE QUOTES  'LIT'
;		IF LITERAL CONTAINS CONTROL CODES ENTIRE STRING IN <> BRACKETS
;		MACRO ALSO ASSEMBLES
;			CR = CARRIAGE RETURN
;			LF = LINE FEED
;			BEL = BELL CODE
;
;		MACRO ASSUMES ADDR ALREADY LOADED TO HL IF ARGUMENT OMITTED
;
PRINT	MACRO	?STRING,LEN,TC
	LOCAL	@OVER,@MESS,PLOOP,PASTCR,@CRLF
CR	SET	0DH
LF	SET	0AH
BEL	SET	07H
	IFB 	<?STRING&LEN&TC>	;;Altered form
	JMP	PASTCR
@CRLF:	DB	CR
	DB	LF
	DB	'$'
PASTCR:	LXI	D,@CRLF
	MVI	C,9
	CALL	5
	ELSE
	IFB	<LEN&TC>
	JMP	@OVER
@MESS:	DB	?STRING
	DB	'$'
@OVER:	LXI	D,@MESS
	MVI	C,9
	CALL	5		;;BDOS ENTRY
	ELSE
	IFB	<TC>		;;Altered form
	IFNB	<?STRING>	;;Altered form
	LXI	D,?STRING	;;POINTER TO STRING
	ENDIF
	MVI	C,9
	CALL	5		;;BDOS ENTRY
	ELSE
	IFNB	<?STRING>	;;Altered form
	LXI	H,?STRING	;;POINTER TO STRING
	ENDIF
	MVI	C,LEN		;;LENGTH OF STRING
PLOOP:	PUSH	B
	PUSH	H
	IF	TC=H
	MOV	A,M		;;GET A BYTE
	HEXOUT			;;CONV TO HEX & OUTPUT
	ELSE
	MOV	E,M		;;GET A BYTE
	MVI	C,2		;;OUT FROM E
	CALL	5
	ENDIF
	POP	H
	POP	B
	INX	H
	DCR	C		;;DECR LENGTH
	JNZ	PLOOP		;;CONTINUE TILL LEN 0
	ENDIF
	ENDIF
	ENDIF
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	HEXOUT MACRO	CONVERT BINARY NO AND OUTPUT TO CONSOLE
;
;	HEXOUT	ADDR
;
;		NUMBER ASSUMED IN A IF NO ARGUMENT
;
HEXOUT	MACRO	ADDR
	LOCAL	OUTCHR,HEXEND
	JMP	HEXEND
HEXPRN:	SAVE	PSW
	RRC
	RRC
	RRC
	RRC			;;SHIFT RIGHT 4
	CALL	OUTCHR
	RESTORE	PSW
OUTCHR: ANI	0FH		;;MASK 4 BITS
	ADI	90H		;;ADD OFFSET
	DAA			;;DEC ADJUST
	ACI	40H		;;ADD OFFSET
	DAA			;;DEC ADJUST
	MOV	E,A		;;TO E FOR OUTPUT
	MVI	C,2		;;CONOUT
	JMP	5		;;CALL BDOS
HEXEND:
HEXOUT	MACRO	?ADDR
	IFNB	<?ADDR>		;;Altered form
	LDA	?ADDR
	ENDIF
	CALL	HEXPRN
	ENDM
	HEXOUT	ADDR
	ENDM
;
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	HEXIN MACRO	CONVERT A NUMBER IN MEMORY FROM HEX TO BINARY
;
;			IF NO ARGUMENT MACRO ASSUMES ADDR OF HEX STRING IN HL
;			ANSWER LEFT IN HL WITH LEAST SIGNIFICANT 8 BITS IN A
;			CARRY SET ON ERROR. CONVERSION STOPS WHEN ZERO IS
;			FOUND IN HEX STRING.
;
HEXIN	MACRO	ADDR
	LOCAL	IN1,IN2,OVERSUB
	JMP	OVERSUB
@HEXIN:	LXI	H,0		;;ZERO NUMBER
IN1:	LDAX	D		;;GET A CHAR
	ORA	A		;;CHECK FOR END OF BUFFER
	RZ
	SUI	'0'		;;CHECK < 0 AND CONVERT TO HEX
	RC
	ADI	'0'-'G'		;;CHECK > F
	RC
	ADI	6
	JP	IN2		;;NO BETWEEN A AND F
	ADI	7
	RC
IN2:	ADI	10
	ORA	A		;;CLEAR CARRY
	MOV	C,A		;;HEX DIGIT TO C
	MVI	B,0		;;ZERO TO B
	DAD	H
	DAD	H
	DAD	H
	DAD	H		;;SHIFT LEFT 4
	DAD	B		;;ADD IN NEW DIGIT
	INX	D		;;INCR BUFFER POINTER
	JMP	IN1		;;RETURN FOR MORE INPUT
OVERSUB:
HEXIN	MACRO	?ADDR
	IFNB	<?ADDR>		;;Altered form
	LXI	D,?ADDR		;;LOAD BUFFER ADDR
	ELSE
	XCHG
	ENDIF
	CALL	@HEXIN
	MOV	A,L		;;LEAST SIGNIFICANT 8 BITS TO A
	ENDM
	HEXIN	ADDR
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	DECOUT MACRO	CONVERT A POSITIVE INTEGER TO DECIMAL AND OUTPUT 
;			TO THE CONSOLE.
;
;	DECOUT	ADDR
;
;		IF ADDR OMITTED, NUMBER ASSUMED TO BE IN HL, ELSE LOADED TO HL
;		LEADING ZEROS SUPRESSED. MAXIMUM NUMBER 65,767
;
DECOUT	MACRO	ADDR
	LOCAL	ENDDEC,DX
	JMP	ENDDEC
@DECOUT:SAVE			;;PUSH STACK
	LXI	B,-10		;;RADIX FOR CONVERSION
	LXI	D,-1		;;THIS BECOMES NO DIVIDED BY RADIX
DX:	DAD	B		;;SUBTRACT 10
	INX	D
	JC	DX
	LXI	B,10
	DAD	B		;;ADD RADIX BACK IN ONCE
	XCHG
	MOV	A,H
	ORA	L		;;TEST FOR ZERO
	CNZ	@DECOUT		;;RECURSIVE CALL
	MOV	A,E
	ADI	'0'		;;CONVERT FROM BCD TO HEX
	MOV	E,A		;;TO E FOR OUTPUT
	CHAROUT			;;CONSOLE OUTPUT
	RESTORE			;;POP STACK
	RET
ENDDEC:
DECOUT	MACRO	?ADDR
	IFNB	<?ADDR>		;;Altered form
	LHLD	?ADDR
	ENDIF
	CALL	@DECOUT		;;CALL THE SUBROUTINE
	ENDM
	DECOUT	ADDR
	ENDM
;
;
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	DECIN MACRO	CONVERT A NUMBER IN MEMORY FROM ASCII TO BINARY
;
;	DECIN	ADDR
;
;		ADDR POINTS TO MEMORY LOCATION OF START OF NO, IF
;		ARG OMITTED POINTER ASSUMED LOADED TO HL
;		MACRO RETURNS WITH CARRY SET IF ALPHABETIC CHAR FOUND
;		CONVERSION STOPS WHEN CHAR LESS THAN ZERO IS FOUND.
;		BINARY NUMBER IS LEFT IN HL, MAXIMUM 65,767
;		LEAST SIGNIFICANT 8 BITS OF NUMBER IN A.
;
DECIN	MACRO	ADDR
	LOCAL	DLOOP,OVERSUB
	JMP	OVERSUB
@DECIN:	LXI	D,0		;;ZERO DE
	XCHG			;;ADDR POINTER TO DE, ZERO TO HL
DLOOP:	LDAX	D		;;GET A ASCII DIGIT
	SUI	'0'		;;CONVERT TO BCD AND TEST
	ANA	A		;;RESET CARRY
	RM			;;TERMINATE CONVERSION IF < ZERO
	CPI	10		;;CHECK LEGITIMATE DIGIT (0-9)
	CMC			;;COMPLEMENT CARRY
	RC			;;RET WITH CARRY SET IF ERROR
	INX	D		;;INCR ADDR POINTER
	DAD	H		;;SHIFT LEFT 1
	PUSH	H		;;SAVE RESULT
	DAD	H
	DAD	H		;;SHIFT LEFT 2
	POP	B		;;NO * 2 TO B
	DAD	B		;;HL NOW CONTAINS 10*NO
	MOV	C,A		;;ADD PRODUCT TO DIGIT
	MVI	B,0
	DAD	B
	JMP	DLOOP		;;BACK FOR ANOTHER DIGIT
OVERSUB:
DECIN	MACRO	?ADDR
	IFNB	<?ADDR>		;;Altered form
	LXI	H,?ADDR
	ENDIF
	CALL	@DECIN		;;CALL THE SUBROUTINE
	MOV	A,L		;;LEAST SIGNIFICANT HALF OF NO TO A
	ENDM
	DECIN	ADDR
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	MOVE MACRO	MOVE A BLOCK FROM SOURCE TO DEST
;
;	MOVE	SOURCE,DEST,COUNT
;
;		SOURCE TO HL	MACRO ASSUMES REGISTERS ALREADY
;		DEST TO DE	LOADED IF ARG OMITTED
;		COUNT TO BC
;
MOVE	MACRO	SOURCE,DEST,COUNT
	LOCAL	OVERSUB
	JMP	OVERSUB
@MOVE:	MOV	A,B
	ORA	C
	RZ			;;EXIT COUNT ZERO
	MOV	A,M		;;GET A BYTE
	STAX	D		;;STORE IT
	INX	H
	INX	D
	DCX	B
	JMP	@MOVE		;;BACK TO MOVE LOOP
OVERSUB:
MOVE	MACRO	SRC,?D,?C
	IFNB	<SRC>		;;Altered form
	LXI	H,SRC
	ENDIF
	IFNB	<?D>		;;Altered form
	LXI	D,?D
	ENDIF
	IFNB	<?C>		;;Altered form
	LXI	B,?C
	ENDIF
	CALL	@MOVE		;;CALL THE MOVE SUBROUTINE
	ENDM
	MOVE	SOURCE,DEST,COUNT
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	FILL MACRO - FILL A BLOCK OF MEMORY WITH A CONSTANT
;
;	FILL	START,STOP,CONSTANT
;
;		CONSTANT OMITTED, FILL WITH 0
;		END OMITTED, FILL ONE BYTE
;
FILL	MACRO	START,STOP,CONST
	LOCAL	@FILL,BLKLEN
BLKLEN:	SET	STOP-START+1
	LXI	H,START		;;LOAD START ADDR
	IFNB	<STOP>		;;Altered form
	IF	BLKLEN GT 255
	LXI	B,BLKLEN	;;LOAD BLOCK LENGTH
	ELSE
	MVI	C,BLKLEN
	ENDIF
	IFNB	<CONST>		;;Altered form
	MVI	E,CONST		;;LOAD CONST IF NOT NULL
	ELSE
	MVI	E,0
	ENDIF
@FILL:	MOV	M,E		;;STORE A BYTE
	INX	H		;;INCR MEMORY POINTER
	IF	BLKLEN GT 255
	DCX	B		;;DECR COUNT
	MOV	A,C		;;TEST LIMIT
	ORA	B
	JNZ	@FILL		;;CONTINUE
	ELSE
	DCR	C
	JNZ	@FILL
	ENDIF
	ELSE
	IFB	<CONST>		;;Altered form
	MVI	M,0		;;STORE A ZERO
	ELSE
	MVI	M,CONST		;;STORE SINGLE BYTE
	ENDIF
	ENDIF
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;
;	MATCH MACRO	COMPARE 2 STRINGS OF SAME LENGTH SET CARRY IF EQUAL
;
;	MATCH	STR1,'LITERAL STRING'
;	MATCH	STR1,STR2,LENGTH
;	MATCH
;
;		DE POINTS TO STR1	MACRO WILL LOAD REG IF ARG
;		HL POINTS TO STR2	PRESENT
;		C CONTAINS LENGTH
;
;		SUBTRACT STR2 FROM STR1 AND SET FLAGS, ZERO INDICATES MATCH.
;		NORMALLY THE SECOND ARG IS A LITERAL STRING AND THE LENGTH
;		IS OMITTED. IF THE LEN ARG IS PRESENT THE SECOND STRING
;		ARG IS ASSUMED TO BE A MEMORY ADDR. IF ALL ARGUMENTS OMITTED
;		REGISTERS ASSUMED ALREADY LOADED.
;
MATCH	MACRO	STR1,STR2,LEN
	LOCAL	OVERSUB,M1
	JMP	OVERSUB
@MATCH:	INR	C		;;PRE INCREMENT COUNT (IT MIGHT BE ZERO)
M1:	DCR	C		;;DECR LENGTH COUNT
	RZ			;;RETURN IF MATCH FOUND
	LDAX	D		;;GET A BYTE FROM ONE STRING
	SUB	M		;;COMPARE WITH OTHER
	RNZ			;;RETURN
	INX	H
	INX	D		;;INCR STRING POINTERS
	JMP	M1		;;TRY SOME MORE
OVERSUB:
MATCH	MACRO	?STR1,?STR2,?LEN
	LOCAL	LITSTR,ENDLIT
	IFB	<?STR1&?STR2&?LEN>	;;Altered form
	CALL	@MATCH
	ELSE
	IFNB	<?STR1>		;;Altered form
	LXI	D,?STR1		;;LOAD STRING1 POINTER
	ENDIF
	IFB	<?LEN>		;;Altered form  -  TEST FOR LITERAL
	MVI	C,ENDLIT-LITSTR	;;LENGTH OF LITERAL STRING
	LXI	H,LITSTR	;;POINTER TO LITERAL
	CALL	@MATCH
	JMP	ENDLIT
LITSTR:	DB	?STR2		;;LITERAL STRING
ENDLIT:				;;END OF STRING
	ELSE
	IFNB	<?STR2>		;;Altered form
	LXI	H,?STR2		;;LOAD POINTER TO STRING2
	ENDIF
	MVI	C,?LEN		;;LOAD STRING LENGTH
	CALL	@MATCH		;;CALL MATCH SUBROUTINE
	ENDIF
	ENDIF
	ENDM
	MATCH	STR1,STR2,LEN
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	INSTR MACRO	SEARCH STRING FOR SUBSTRING AND SET CARRY IF FOUND
;
;	INSTR	STRING,LENGTH,SUBSTR
;
;		HL	POINTS TO STRING
;		DE	POINTS TO SUBSTRING
;		B	CONTAINS STRING LENGTH
;		C	CONTAINS SUBSTRING LENGTH
;
;		MACRO RETURNS POINTER TO END OF SUBSTRING IN HL
;
INSTR	MACRO	STRING,LENGTH,SUBSTR
	LOCAL	OVERSUB,S1,SSX
	JMP	OVERSUB
@INSTR:	MOV	A,B		;;STRING LENGTH
	SUB	C		;;SUBTRACT SUBSTR LENGTH
	CMC			;;COMP CARRY
	RNC			;;ERROR RETURN SUBSTR > STRING
	MOV	B,A		;;NEW STRING LIMIT TO B
S1:	SAVE
	MATCH
	RESTORE
	JZ	SSX		;;MATCH IF ZERO ON RET
	ANA	A		;;RESET CARRY
	DCR	B		;;BYTES LEFT
	RM			;;FINISHED IF MINUS, NO MATCH
	INX	H		;;INCR STRING POINTER
	JMP	S1		;;TRY AGAIN
SSX:	MVI	B,0		;;SET D TO 0
	DAD	B
	STC			;;SET CARRY
	RET
OVERSUB:
INSTR	MACRO	?STR,?LEN,?SUBSTR
	LOCAL	LITSTR,ENDLIT
	IFNB	<?STR>		;;Altered form
	LXI	H,?STR
	ENDIF
	MVI	B,?LEN
	MVI	C,ENDLIT-LITSTR
	LXI	D,LITSTR
	CALL	@INSTR
	JMP	ENDLIT
LITSTR:	DB	?SUBSTR
ENDLIT:
	ENDM
	INSTR	STRING,LENGTH,SUBSTR
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	SCAN MACRO	SCAN A STRING UNTIL A CHAR IS FOUND, SKIP BLANKS
;			AND CONTROL CHARACTERS
;
;			CARRY SET IF NUMERIC, CARRY OFF IF ALPHABETIC
;
;
SCAN	MACRO	ADDR
	LOCAL	OVERSUB
	JMP	OVERSUB
@SCAN:	MOV	A,M		;;GET A BYTE
	CPI	21H		;;SPACE OR LESS?
	RP
	INX	H		;;INCR POINTER
	JMP	@SCAN		;;KEEP SEARCHING
OVERSUB:
SCAN	MACRO	?ADDR
	IFNB	<?ADDR>		;;Altered form
	LXI	H,?ADDR
	ENDIF
	CALL	@SCAN		;;CALL SUBROUTINE
	CPI	3AH		;;NUMBER OR ALPHA
	ENDM
	SCAN	ADDR
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	DISKIO MACRO	EXECUTE BDOS DISK ACCESS PRIMITIVES
;
;	DISKIO	FUNCTION,PARAMETER
;
;		NO	FUNCTION	ENTRY PARAM
;
;		12	LIFTHEAD
;		13	INITIAL
;		14	LOGIN		DISK NO 0 - 1
;		15	OPEN		FCB
;		16	CLOSE		FCB
;		17	SEARCH		FCB
;		18	SERNXT		FCB
;		19	DELETE		FCB
;		20	READ		FCB
;		21	WRITE		FCB
;		22	MAKE		FCB
;		23	RENAME		FCB
;		24	?LOGIN
;		25	?DRIVE
;		26	SETDMA		BUFFER
;		27	?ALLOC
;		SEE CP/M INTERFACE GUIDE FOR DETAILED INFORMATION ON THE
;		DISK ACCESS PRIMITIVES
;
;	DISKIO	READ,FCB	(TYPICAL MACRO CALL)
;
DISKIO	MACRO	FUNCTION,PARAMETER
LIFTHEAD	SET	12
INITIAL		SET	13
LOGIN		SET	14
OPEN		SET	15
CLOSE		SET	16
SEARCH		SET	17
SERNXT		SET	18
DELETE		SET	19
READ		SET	20
WRITE		SET	21
MAKE		SET	22
RENAME		SET	23
?LOGIN		SET	24
?DRIVE		SET	25
SETDMA		SET	26
?ALLOC		SET	27
;
?C	SET	FUNCTION
	IFNB	<PARAMETER>	;;Altered form
	LXI	D,PARAMETER
	ENDIF
	MVI	C,?C
	CALL	5		;;BDOS ENTRY
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	CALLBIOS MACRO	CALL BIOS ROUTINES DIRECTLY
;
;	CALLBIOS	FUNCTION,PARAM
;
CALLBIOS	MACRO	FUNCT,PARAM
	LOCAL	@CALL
;
DCOLD	SET	00H
DWBOOT	SET	03H
DSTAT	SET	06H
DCONIN	SET	09H
DCONOUT	SET	0CH		;;CHAR IN C
DLIST	SET	0FH		;;CHAR IN C
DPUNCH	SET	12H
DREADER	SET	15H
DHOME	SET	18H
DSELDSK	SET	1BH
DSETTRK	SET	1EH
DSETSEC	SET	21H		;;SECTOR NO IN C
DSETDMA	SET	24H		;;DMA ADDR IN BC
DREAD	SET	27H
DWRITE	SET	2AH
;
?F	SET	FUNCT
	IFNB	<PARAM>		;;Altered form
	MVI	C,PARAM
	ENDIF
	LHLD	1		;;ADDR OF BIOS
	MVI	L,?F		;;JUMP OFFSET
	SHLD	@CALL+1		;;MODIFY CALL ADDR
@CALL:	CALL	0
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	DLOAD MACRO	DOUBLE PRECISION INDEXED LOAD HL
;
;		LOAD (ADDR + INDX) TO HL
;
DLOAD	MACRO	ADDR,INDX
	IFB	<INDX>		;;Altered form
	LHLD	ADDR
	ELSE
	LHLD	INDX
	LXI	D,ADDR
	DAD	D
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG
	ENDIF
	ENDM
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	CPHL MACRO	SUBTRACT DE FROM HL AND SET FLAGS
;
CPHL	MACRO
	LOCAL	@END
	MOV	A,H
	CMP	D		;;COMPARE HIGH BYTES
	JNZ	@END
	MOV	A,L
	CMP	E		;;COMPARE LOW BYTES
@END:	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	DJZ MACRO	DOUBLE PRECISION TEST HL AND JUMP ON ZERO
;
DJZ	MACRO	ADDR
	MOV	A,H
	ORA	L
	JZ	ADDR
	ENDM
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	DSTORE MACRO	DOUBLE PRECISION INDEXED STORE HL
;
;		STORE (HL) IN (ADDR + INDX)
;
DSTORE	MACRO	ADDR,INDX
	IFB	<INDX>		;;Altered form
	SHLD	ADDR
	ELSE
	SAVE	H
	LHLD	INDX
	XCHG
	LXI	H,ADDR
	DAD	D
	RESTORE	D
	MOV	M,E
	INX	H
	MOV	M,D
	ENDIF
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	INDEX MACRO	INDEX AN ADDRESS POINTER BY A CONSTANT
;
;	INDEX	POINTER,INCR
;
INDEX	MACRO	POINTER,INCR
	LHLD	POINTER
	LXI	D,INCR
	DAD	D		;;DOUBLE ADD
	SHLD	POINTER
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	FILFCB	MACRO	FILL IN THE ID FIELDS OF FCB
;
;	FILFCB	FCB,IDSTRING
;
;		IDSTRING CONTAINS FILE NAME AND TYPE  (FILNAM.TYP)
;		CARRY SET IF ERROR  (NAME TOO LONG)
;
FILFCB	MACRO	FCB,IDSTRING
	LOCAL	OVERSUB,F1,F2,F3,F4,F5,F6
	JMP	OVERSUB
@FLFCB: MVI	M,0		;;CLEAR FIRST BYTE OF FCB
	INX	H
	PUSH	H		;;SAVE POINTER TO NAME
	MVI	C,11		;;SIZE OF ID FIELD
	MVI	A,' '		;;SPACE TO A
F1:	MOV	M,A		;;FILL NAME WITH SPACES
	INX	H
	DCR	C
	JNZ	F1
	POP	H		;;RESTORE NAME POINTER
	MVI	C,8		;;MAXIMUM SIZE OF NAME
F2:	LDAX	D		;;GET BYTE FROM ID FIELD
	CPI	' '		;;LEADING SPACES?
	JNZ	F3
	INX	D		;;SKIP LEADING SPACES
	JMP	F2
F3:	LDAX	D		;;GET ID BYTE
	CPI	0		;;ZERO END OF FIELD
	RZ
	CPI	' '		;;SPACE END OF FIELD
	RZ
	CPI	'.'		;;PERIOD TYPE SEPARATOR
	JZ	F4		;;DO TYPE
	MOV	M,A		;;STORE NAME BYTE
 	INX	H
	INX	D		;;INCR POINTERS
	DCR	C		;;DECR MAXIMUM COUNT
	JP	F3		;;LOOP BACK
	STC			;;SET CARRY NAME TOO LARGE
	RET
F4:	INX	D		;;SKIP THE PERIOD
	MOV	A,C
	ORA	A
	JZ	F6		;;TEST C FOR ZERO
F5:	INX	H
	DCR	C
	JNZ	F5		;;INDEX TO TYPE FIELD
F6:	MVI	C,3		;;SIZE OF TYPE FIELD
F7:	LDAX	D		;;GET ID BYTE
	CPI	0		;;ZERO?
	RZ			;;FINISHED
	CPI	' '		;;SPACE?
	RZ
	MOV	M,A		;;STORE TYPE BYTE
	INX	H
	INX	D		;INCR POINTERS
	DCR	C		;;DECR MAX COUNT
	JNZ	F7		;;LOOP BACK
	RET
OVERSUB:
FILFCB	MACRO	?FCB,?ID
	IFNB	<?ID>		;;Altered form
	LXI	D,?ID
	ENDIF
	IFNB	<?FCB>		;;Altered form
	LXI	H,?FCB
	ENDIF
	CALL	@FLFCB
	XCHG
	ENDM
	FILFCB	FCB,IDSTRING
	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	SETTRK MACRO	SET AND TEST TRACK NUMBER
;
;			CARRY SET IF > 76
;
SETTRK	MACRO	TRKNO
	LOCAL	ENDTRK
	IFNB	<TRKNO>		;;Altered form
	LDA	TRKNO
	ENDIF
	CPI	77
	CMC
	JC	ENDTRK
	MOV	C,A		;;TRACK NO TO C
	CALLBIOS DSETTRK
ENDTRK:	ENDM
;
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	SETSEC MACRO	SET AND TEST SECTOR NUMBER
;
;		RETURN WITH CARRY SET < 1 OR > 26
;
SETSEC	MACRO	SECNO
	LOCAL	ENDSEC
	IFNB	<SECNO>		;;Altered form
	LDA	SECNO
	ENDIF
	ORA	A		;CHECK ZERO
	STC
	JZ	ENDSEC
	CPI	27		;CHECK > 26
	CMC
	JC	ENDSEC
	MOV	C,A		;MOVE TO C
	CALLBIOS DSETSEC
ENDSEC:	ENDM
;	. . . . . . . . . . . . . . . . . . . . . . . . . . . .
;
;	HALF MACRO	DIVIDES A 16 BIT NUMBER BY 2
;
HALF	MACRO	I
	LOCAL	OVER
	JMP	OVER
@HALF:	XRA	A		;;CLEAR CARRY
	MOV	A,H
	RAR			;;SHIFT UPPER HALF
	MOV	H,A
	MOV	A,L
	RAR			;;SHIFT LOWER HALF
	MOV	L,A
	RET
OVER:
HALF	MACRO	?I
	IFNB	<?I>		;;Altered form
	LHLD	?I
	ENDIF
	CALL	@HALF
	ENDM
	HALF	I
	ENDM
.LIST
